
# wxPython 选择源目录 目标目录 提交按钮 ,按gps信息中的城市建目录，拍摄日期年月建子目录分类存放照片。
# 没有GPS城市信息的的存放在noexitcity目录下的拍摄年月子目录中。
# 由于使用高德地图，所以只适合在国内拍摄的照片。
# pyinstaller -F d:\pythonp\wx2\copy_jpg_to_gps_ym_dir_v1_0.py
# pyinstaller -F copy_jpg_to_gps_ym_dir_v1_0.py
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pytz
# version 1.5 加入对子目录的处理

import wx
import os
import sys
from pathlib import Path
from shutil import copy
from datetime import datetime
import time

import exifread
import subprocess  # 用于调用 exiftool
from PIL import Image
from PIL.ExifTags import TAGS
import pillow_heif
from pillow_heif import register_heif_opener
import io
import exiftool
import pytz
import requests
import json
# 导入高德地图配置参数 api_key
import gd_config

# 创建register_heif_opener模块里的一个类然后再Image.open打开HEIC文件
register_heif_opener()

class MyFramecityymapp(wx.Frame):
    def __init__(self, *args, **kw):
        super(MyFramecityymapp, self).__init__(*args, **kw)

        self.InitUI()

    def InitUI(self):
        panel = wx.Panel(self)

        # 创建选择源目录的按钮和文本框
        src_label = wx.StaticText(panel, label="源目录:")
        self.src_path = wx.TextCtrl(panel)
        src_button = wx.Button(panel, label="选择源目录")
        src_button.Bind(wx.EVT_BUTTON, self.OnSelectSrc)

        # 创建选择目标目录的按钮和文本框
        dest_label = wx.StaticText(panel, label="目标目录:")
        self.dest_path = wx.TextCtrl(panel)
        dest_button = wx.Button(panel, label="选择目标目录")
        dest_button.Bind(wx.EVT_BUTTON, self.OnSelectDest)

        # 创建提交按钮
        submit_button = wx.Button(panel, label="提交")
        submit_button.Bind(wx.EVT_BUTTON, self.OnSubmit)

        # 创建提交按钮
        #submit_button = wx.Button(panel, label="提交")
        #submit_button.Bind(wx.EVT_BUTTON, self.OnSubmit)

        # 创建退出按钮
        exit_button = wx.Button(panel, label="退出")
        exit_button.Bind(wx.EVT_BUTTON, self.on_exit)

        # 创建进度条
        self.progress = wx.Gauge(panel, range=100, pos=(20, 150), size=(550, 25))

        # 布局
        sizer = wx.GridBagSizer(6, 6)
        sizer.Add(src_label, pos=(0, 0), flag=wx.LEFT|wx.TOP, border=10)
        sizer.Add(self.src_path, pos=(0, 1), span=(1, 3), flag=wx.EXPAND|wx.TOP|wx.RIGHT, border=10)
        sizer.Add(src_button, pos=(0, 4), flag=wx.TOP|wx.RIGHT, border=10)

        sizer.Add(dest_label, pos=(1, 0), flag=wx.LEFT|wx.TOP, border=10)
        sizer.Add(self.dest_path, pos=(1, 1), span=(1, 3), flag=wx.EXPAND|wx.TOP|wx.RIGHT, border=10)
        sizer.Add(dest_button, pos=(1, 4), flag=wx.TOP|wx.RIGHT, border=10)

        sizer.Add(submit_button, pos=(2, 0), span=(1, 2), flag=wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, border=10)

        sizer.Add(exit_button, pos=(2, 2), span=(1, 2), flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10)

        sizer.AddGrowableCol(1)
        panel.SetSizer(sizer)

        self.SetSize((600, 250))
        self.SetTitle('照片按城市及拍摄日期年月分类存放程序。')
        self.Centre()

        self.Show()

    def OnSelectSrc(self, event):
        dlg = wx.DirDialog(self, "选择源目录", style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            self.src_path.SetValue(dlg.GetPath())
        dlg.Destroy()

    def OnSelectDest(self, event):
        dlg = wx.DirDialog(self, "选择目标目录", style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            self.dest_path.SetValue(dlg.GetPath())
        dlg.Destroy()

    def OnSubmit(self, event):
        # 处理业务部分
        #for i in range(101):
        #   time.sleep(0.05)  # 模拟长时间操作
        #   self.progress.SetValue(i)
        #   wx.Yield()  # 允许UI更新

        src = self.src_path.GetValue()
        dest = self.dest_path.GetValue()
        if os.path.isdir(src) and os.path.isdir(dest):
            #wx.MessageBox(f"源目录: {src}\n目标目录: {dest}", "提交信息", wx.OK | wx.ICON_INFORMATION)
            # 提交处理数据
            source_dir = src
            destination_dir = dest
            # 示例用法
            if self.check_directory_exists(source_dir):
                print(f"源文件目录: {source_dir}")
            else:
                print(f"### 源文件目录 {source_dir} 不存在！")
                sys.exit(1)  # 停止程序执行，并返回一个非零的退出状态码

            if self.check_directory_exists(destination_dir):
                print(f"目标文件目录: {destination_dir}")
            else:
                print(f"### 目标文件目录 {destination_dir} 不存在！")
                sys.exit(1)  # 停止程序执行，并返回一个非零的退出状态码

            # 处理分类存放程序
            # 使用示例
            # source_dir = 'Z:\Xiaomi 24069RA21C Camera Backup'  # 源目录路径
            # source_dir = 'D:\\redmi-ym\\2021-10'  # 源目录路径
            source_dir = source_dir
            # destination_dir = 'D:\\redmi-ym'  # 目标目录路径
            destination_dir = destination_dir
            if source_dir == destination_dir:
                print(f"#源目录和目的目录相同！")
                wx.MessageBox("源目录和目的目录相同", "错误", wx.OK | wx.ICON_ERROR)
                sys.exit(1)  # 停止程序执行，并返回一个非零的退出状态码

            #files = []
            # 获取当前时间并格式化
            current_time = time.strftime("%Y%m%d_%H%M%S")

            # 创建文件名
            logfile_name = f"log_{current_time}.txt"
            logfile_path = os.path.join(destination_dir, logfile_name)
            # 打开文件以写入模式
            logfile = open(logfile_path, 'w')

            total_files = 0
            total_filenum = 0
            #sorted_list = sorted(os.walk(source_dir))
            for root, dirs, filenames in os.walk(source_dir):
                print('\n目录名：', root,"\n")

                # 写入文件
                logfile.write(f"\n目录名：{root}\n")

                # 统计目录下的文件数
                file_count = self.count_files_in_directory(root)
                # 对每一个文件逐一处理
                for filename in filenames:
                    # files.append(os.path.join(root, filename))
                    #    total_files += 1
                    #    print(total_files, '.', os.path.join(root, filename))
                    if filename == ".DS_Store":
                        file_count =file_count  -1

                total_files = total_files + file_count
                # 设置进度条的最大值
                #progress_bar['value'] = 0
                #progress_bar['maximum'] = file_count
                #start_progress(progress_bar)
                # 动态设置进度条的 range
                new_range = file_count
                self.progress.SetRange(new_range)
                # 处理一个目录下的所有文件
                filenum = self.organize_files_by_date(root, destination_dir,logfile)
                total_filenum = total_filenum + filenum
                # 示例用法
                # file_count = count_files_in_directory(source_dir)

            print(f"源目录 {source_dir} 中的文件个数为: {total_files}")
            print(f"拷贝文件个数为: {total_filenum}")
            print('copy file ending...')
            # 写入文件
            logfile.write(f"源目录 {source_dir} 中的文件个数为: {total_files}\n")
            logfile.write(f"拷贝文件个数为: {total_filenum}\n")
            logfile.write('copy file ending...')
            # 确保文件被关闭
            logfile.close()

            wx.MessageBox("数据处理完成！", "信息", wx.OK | wx.ICON_INFORMATION)
        else:
            wx.MessageBox("请选择有效的目录", "错误", wx.OK | wx.ICON_ERROR)


    def organize_files_by_date(self,source_dir, destination_dir,logfile):
        # 创建目标目录，如果不存在的话
        Path(destination_dir).mkdir(parents=True, exist_ok=True)
        filenum = 0
        # 遍历源目录下的所有文件
        sorted_list = sorted(os.listdir(source_dir))
        for filename in sorted_list:
            if filename == ".DS_Store":
                continue

            file_path = os.path.join(source_dir, filename)

            # 如果是文件并且不在目标目录中，则按日期移动
            # and not os.path.exists(os.path.join(destination_dir, filename))
            if os.path.isfile(file_path) :
                filenum = filenum + 1

                """
                模拟进度条增加的过程
                :param progress_bar: ttk.Progressbar对象
                """
                #update_progress_bar(progress_bar, 1)

                self.progress.SetValue(filenum)
                wx.Yield()  # 允许UI更新

                self.copy_one_file(filenum,filename,file_path, destination_dir, logfile)

        return filenum

    def copy_one_file(self, filenum,filename, file_path, destination_dir,logfile):
        # 处理一个文件
        # 获取文件的创建时间
        creation_time = os.path.getmtime(file_path)
        file_datetime = datetime.fromtimestamp(creation_time)
        # 文件是.jpg
        if self.is_jpg_file(file_path):
            # 首先检查是否有gps信息
            err,destination_dir = self.make_city_dir(file_path, destination_dir)

            # 打开照片文件，单独处理
            with open(file_path, 'rb') as file:
                # 使用exifread读取EXIF信息
                tags = exifread.process_file(file)

                # 尝试读取拍摄日期
                try:
                    # 如果拍摄日期存在，它通常在EXIF格式的"DateTimeOriginal"标签中
                    date_taken = tags['EXIF DateTimeOriginal'].printable
                    file_datetime = datetime.strptime(date_taken, "%Y:%m:%d %H:%M:%S")
                    creation_time = int(file_datetime.timestamp())
                    # print(date_taken)
                    # print(f"Date Taken: {date_taken}")
                except KeyError:
                    # 如果标签不存在，则打印错误消息
                    # print("Date Taken tag not found.")
                    date_taken = ''
        # 文件是.png
        elif self.is_png_file(file_path):
            # 首先检查是否有gps信息
            err,destination_dir = self.make_city_dir(file_path, destination_dir)
            # 打开照片文件，单独处理
            with open(file_path, 'rb') as file:
                # 使用exifread读取EXIF信息
                tags = exifread.process_file(file)
                if tags:
                    # 尝试读取拍摄日期
                    try:
                        # 如果拍摄日期存在，它通常在EXIF格式的"DateTimeOriginal"标签中
                        date_taken = tags['EXIF DateTimeOriginal'].printable
                        file_datetime = datetime.strptime(date_taken, "%Y:%m:%d %H:%M:%S")
                        creation_time = int(file_datetime.timestamp())
                        # print(date_taken)
                        # print(f"Date Taken: {date_taken}")
                    except KeyError:
                        # 如果标签不存在，则打印错误消息
                        # print("Date Taken tag not found.")
                        date_taken = ''
        # 文件是.raw
        elif self.is_raw_file(file_path):
            # 首先检查是否有gps信息
            err,destination_dir = self.make_city_dir(file_path, destination_dir)
            # 打开照片文件，单独处理
            date_taken = self.get_exif_info(file_path)
            if date_taken != '':
                file_datetime = datetime.strptime(date_taken, "%Y:%m:%d %H:%M:%S")
                creation_time = int(file_datetime.timestamp())
            else:
                date_taken = ''

        # 是 HEIC 文件
        elif any([file_path.lower().endswith(ext) for ext in [".heic"]]):
            # 首先检查是否有gps信息
            err,destination_dir = self.make_city_dir(file_path, destination_dir)

            datetime_original = self.get_datetime_original(file_path)
            if datetime_original:
                # print(file_path, "【时间】", datetime_original)
                # print('Year:', datetime_original[0:4], 'Month:', datetime_original[5:7])
                # year = datetime_original[0:4]
                # month = year + "-" + datetime_original[5:7]
                file_datetime = datetime.strptime(datetime_original, "%Y:%m:%d %H:%M:%S")
                creation_time = int(file_datetime.timestamp())
            else:
                print('未找到拍摄日期和时间信息')
        # 是 mov mp4 文件
        elif self.is_mov_file(file_path):
            # 首先检查是否有gps信息
            err,destination_dir = self.make_city_dir(file_path, destination_dir)

            datetime_original = self.get_movfile_date(file_path)
            if datetime_original != "err":
                file_datetime = datetime.strptime(datetime_original, "%Y:%m:%d %H:%M:%S")
                creation_time = int(file_datetime.timestamp())
        else:
            # 其他文件，构建目标子目录的路径 建立城市目录
            city_string = 'notexitcity'
            dest_subdir = os.path.join(destination_dir, f"{city_string}")
            # 创建子目录，如果不存在的话
            Path(dest_subdir).mkdir(parents=True, exist_ok=True)
            destination_dir = dest_subdir

        print(f' {filenum}, 原文件及路径：{file_path}, 文件拍摄或修改日期：{file_datetime}')

        # 构建目标子目录的路径
        dest_subdir = os.path.join(destination_dir, f"{file_datetime.year}-{file_datetime.month}")
        # 创建子目录，如果不存在的话
        Path(dest_subdir).mkdir(parents=True, exist_ok=True)

        # 将文件复制到子目录
        copy(file_path, dest_subdir)

        # 修改文件的修改时间
        file_pathd = os.path.join(dest_subdir, filename)

        # filed = Path(file_pathd)
        # filed.touch(times=(creation_time, creation_time))
        os.utime(file_pathd, (creation_time, creation_time))
        print('目标目录：',dest_subdir)
        # 写入文件
        logfile.write(f"{filenum}, 原文件及路径： {file_path}, 文件拍摄或修改日期：{file_datetime}\n")
        logfile.write(f"目标目录： {dest_subdir}\n")
        return

    def make_city_dir(self, file_path,destination_dir):
        # 建立 城市目录
        err, latitude, longitude = self.get_gps_info(file_path)
        if err == '1':
            # print(f'该文件原有GPS信息：{longitude},{latitude}')
            err, city_string = self.get_gps_city(latitude, longitude)
            if err == '1':
                #print(f'该文件城市信息：{city_string}')
                # 构建目标子目录的路径 建立城市目录
                dest_subdir = os.path.join(destination_dir, f"{city_string}")
                # 创建子目录，如果不存在的话
                Path(dest_subdir).mkdir(parents=True, exist_ok=True)
                destination_dir = dest_subdir
            else:
                # 构建目标子目录的路径 建立城市目录
                dest_subdir = os.path.join(destination_dir, f"{city_string}")
                # 创建子目录，如果不存在的话
                Path(dest_subdir).mkdir(parents=True, exist_ok=True)
                destination_dir = dest_subdir

            return '1',destination_dir
        else:
            # 构建目标子目录的路径 建立城市目录
            city_string = 'notexitcity'
            dest_subdir = os.path.join(destination_dir, f"{city_string}")
            # 创建子目录，如果不存在的话
            Path(dest_subdir).mkdir(parents=True, exist_ok=True)
            destination_dir = dest_subdir
            return '0', destination_dir

    def get_gps_info(self, file_path):
        try:
            # 取完整的 EXIF 信息
            #result = subprocess.check_output(["exiftool", file_path], universal_newlines=True)
            # 创建 ExifTool 对象
            x1 = '1'  # 假设没有 GPS 信息
            with exiftool.ExifToolHelper() as et:
                metadata_list = et.get_metadata(file_path)
                if isinstance(metadata_list, list):
                    for metadata in metadata_list:
                        err,gps_latitude, gps_longitude, gps_latitude_ref, gps_longitude_ref = self.extract_gps(metadata,file_path)
                        if err == '0':
                            x1 = '1'
                            break  # 找到第一个有效的 GPS 信息就退出
                        if gps_latitude and gps_longitude:
                            x1 = '0'
                            break  # 找到第一个有效的 GPS 信息就退出

            # 如果有 GPS 信息，处理坐标
            gpsif = x1
            if x1 == '0':
                latitude = self.convert_to_degrees2(gps_latitude)
                longitude = self.convert_to_degrees2(gps_longitude)

                # 根据参考方向调整坐标值
                if gps_latitude_ref == "S":
                    latitude = -latitude
                if gps_longitude_ref == "W":
                    longitude = -longitude
                #print(f'该文件原有GPS信息：{longitude},{latitude}')
                return '1',latitude, longitude
            else:
                #latitude = ''
                #longitude = ''
                #return None
                return '0', '', ''
            # 设置 EXIF 文本框的值
            #print(result)
        except subprocess.CalledProcessError as e:
            # 捕获异常并设置错误信息
            print(f"获取 EXIF 信息时出错: {e}")
            #return None
            return '0', '', ''
        except Exception as ex:
            # 捕获其他异常
            print(f"发生错误: {ex}")
            #return None
            return '0', '', ''

    # 将 GPS 坐标转换为浮点数
    def convert_to_degrees2(self, value):
        # 检查输入的值是否为浮点数或整数
        if isinstance(value, (float, int)):
            return value  # 直接返回浮点数或整数
        # 检查输入的值是否为字符串
        elif isinstance(value, str):
            # 从字符串中解析出度、分、秒
            parts = value.split(' ')
            d = float(parts[0])  # 解析度
            m = float(parts[1])  # 解析分
            s = float(parts[2])  # 解析秒
            # 将度、分、秒转换为浮点数表示的度
            return d + (m / 60.0) + (s / 3600.0)
        # 检查输入的值是否为列表
        elif isinstance(value, list):
            d, m, s = value  # 解包列表中的度、分、秒
            # 将度、分、秒转换为浮点数表示的度
            return d + (m / 60.0) + (s / 3600.0)
        else:
            # 如果输入值的格式不正确，抛出异常
            raise ValueError("无法解析的 GPS 坐标格式")

    # 提取 GPS 信息的函数
    def extract_gps(self, metadata, file_path):
        # print(metadata)
        if "EXIF:GPSLatitude" in metadata:
            return (
                '1',
                metadata.get("EXIF:GPSLatitude"),
                metadata.get("EXIF:GPSLongitude"),
                metadata.get("EXIF:GPSLatitudeRef"),
                metadata.get("EXIF:GPSLongitudeRef")
            )
        else:
            return '0', '', '', '', ''

    def get_gps_city(self, latitude, longitude):

        #高德key
        gd_api_key = gd_config.gd_api_key

        #print(f' 坐标：{latitude},{longitude}')
        # 转换为 GCJ-02 坐标 修正
        url = f'https://restapi.amap.com/v3/assistant/coordinate/convert?key={gd_api_key}&locations={longitude},{latitude}&coordsys=gps&output=json'
        #print(url)
        response = requests.get(url)
        #print(response)
        if response.status_code == 200:
            data = json.loads(response.text)
            if data['status'] == '1':
                # 转换后的高德坐标
                # {"status":"1","info":"ok","infocode":"10000","locations":"117.163480631511,34.228663194445"}
                amap_location = data['locations'] #[0]
                # 117.163480631511,34.228663194445
                #print(f"高德坐标: {amap_location}")

                # 根据参考方向调整坐标值
                #if gps_latitude_ref == "S":
                    #latitude = -latitude
                #if gps_longitude_ref == "W":
                   # longitude = -longitude

                # 使用高德地图API将 GPS 坐标转换为城市名称
                url = f"https://restapi.amap.com/v3/geocode/regeo?output=json&location={amap_location}&key={gd_api_key}&radius=1000&extensions=all"
                response = requests.get(url)
                data = response.json()

                # 提取城市名称
                if data.get("status") == "1" and "regeocode" in data:
                    address_component = data["regeocode"].get("addressComponent", {})
                    city = address_component.get("city", "")
                    province = address_component.get("province", "")
                    district = address_component.get("district", "")
                    country = address_component.get("country", "")
                    township = address_component.get("township", "")
                    street = address_component.get("streetNumber", {}).get("street", "")

                    if city:
                        # 添加拍摄位置到结果中
                        #result = f" 拍摄于: {country}, {province}, {city}, {district}, {street}, {township} "
                        #print(result)
                        city_string = province + '_' + city
                        return '1',city_string
                    else:
                        return '0', 'notexitcity'
                else:
                    return '0', 'notexitcity'

    def get_exif_info(self, file_path):
        try:
            # 取完整的 EXIF 信息
            #result = subprocess.check_output(["exiftool", file_path], universal_newlines=True)

            # 字段名替换字典
            field_replacements = {
                "Media Create Date": "\n媒体建立时间",
                "Date/Time Original": "\n拍摄时间",
                "File Modification Date/Time": "\n文件修改时间",
                "Lens ID": "镜头型号",
                "Lens Make": "镜头制造商",
                "Android Make": "手机制造商",
                "Make ": "设备制造商 ",
                "Camera Model Name": "设备型号",
                "Lens Model": "镜头型号",
                "Lens Type": "镜头类型"
            }
            # 替换提示为中文
            #for en_field, zh_field in field_replacements.items():
            #    result = result.replace(en_field, zh_field)

            # 创建 ExifTool 对象
            x1 = '1'  # 假设没有 GPS 信息
            with exiftool.ExifToolHelper() as et:
                metadata_list = et.get_metadata(file_path)
                if isinstance(metadata_list, list):
                    for metadata in metadata_list:
                        #print(metadata)
                        time_original = metadata.get("EXIF:DateTimeOriginal")
                        OffsetTime = metadata.get("EXIF:OffsetTime")
                        OffsetTimeOriginal = metadata.get("EXIF:OffsetTimeOriginal")
                        #FileModifyDate = metadata.get("File:FileModifyDate")
                        FileModifyDate = os.path.getmtime(file_path)
                        #FileModifyDate = datetime.fromtimestamp(FileModifyDate)

                        if time_original == None:
                            # 文件没有拍照日期，不修改gps信息
                            time_original = FileModifyDate
                            #print("==",time_original, OffsetTime, OffsetTimeOriginal, FileModifyDate)
                            return ''
                        else:
                            return time_original
        except subprocess.CalledProcessError as e:
            # 捕获异常并设置错误信息
            print(f"获取 EXIF 信息时出错: {e}")
            return '' #None
        except Exception as ex:
            # 捕获其他异常
            print(f"发生错误: {ex}")
            return '' #None

    def is_jpg_file(self,filename):
        #return filename.lower().endswith('.jpg')
        # 将文件名转换为小写，并检查是否以'.jpg'或'.jpeg'结尾
        return filename.lower().endswith(('.jpg', '.jpeg'))

    def is_png_file(self,filename):
        # 将文件名转换为小写，并检查是否以'.jpg'或'.jpeg'结尾
        #return filename.lower().endswith(('.jpg', '.jpeg'))
        return filename.lower().endswith('.png')

    def is_raw_file(self,filename):
        # 将文件名转换为小写，并检查是否以'.jpg'或'.jpeg'结尾
        return filename.lower().endswith(('.raw', '.cr', '.cr2', '.cr3', '.nef', '.arw', '.dng', '.orf', '.raf', '.rw2', '.pef', '.srw'))

    def is_mov_file(self,filename):
        #return filename.lower().endswith('.jpg')
        # 将文件名转换为小写，并检查是否以'.jpg'或'.jpeg'结尾
        return filename.lower().endswith(('.mov', '.mp4'))

    def count_files_in_directory(self,directory_path):
        try:
            # 获取目录中的所有文件和子目录
            entries = os.listdir(directory_path)
            # 过滤出文件（非子目录）
            files = [entry for entry in entries if os.path.isfile(os.path.join(directory_path, entry))]
            # 返回文件个数
            return len(files)
        except Exception as e:
            print(f"读取目录时发生错误: {e}")
            return 0

    def update_progress_bar(self,progress_bar, increment):
        """
        更新进度条的函数
        :param progress_bar: ttk.Progressbar对象
        :param increment: 进度条增加的值
        """
        current_value = progress_bar['value']
        max_value = progress_bar['maximum']
        new_value = current_value + increment
        if new_value > max_value:
            new_value = max_value
        progress_bar['value'] = new_value
        root.update_idletasks()  # 更新界面

    def start_progress(self,progress_bar):
        """
        模拟进度条增加的过程
        :param progress_bar: ttk.Progressbar对象
        """
        for i in range(101):
            self.update_progress_bar(progress_bar, 1)
            root.after(100)  # 暂停100毫秒

    def check_directory_exists(self,directory_path):
        """
        检查目录是否存在
        :param directory_path: 目录路径
        :return: 如果目录存在返回True，否则返回False
        """
        return os.path.isdir(directory_path)

    def on_exit(self, event):
        self.Close(True)

    # 获取HEIC格式文件"拍摄日期"的函数
    def get_datetime_original(self,image_path):
        image = Image.open(image_path)
        fstream = io.BytesIO(image.info["exif"][6:])
        exifdata = exifread.process_file(fstream, details=False)
        imageDateTime = str(exifdata.get("Image DateTime"))

        return imageDateTime

    def convert_utc_to_china_time(self,utc_time_str):
        # 解析UTC时间字符串
        #utc_time = datetime.strptime(utc_time_str, "%Y-%m-%dT%H:%M:%S%z")
        utc_time = datetime.strptime(utc_time_str, "%Y:%m:%d %H:%M:%S")

        # 创建UTC时区对象
        utc_timezone = pytz.timezone('UTC')

        # 将UTC时间转换为UTC时区对象
        utc_time = utc_timezone.localize(utc_time)

        # 创建中国时区对象
        china_timezone = pytz.timezone('Asia/Shanghai')

        # 将UTC时间转换为中国时间
        china_time = utc_time.astimezone(china_timezone)

        # 去掉时区信息，只保留时间部分
        china_time_str = china_time.strftime("%Y:%m:%d %H:%M:%S")

        return china_time_str

    # 通过exiftool获取mov mp4文件的建立日期
    def get_movfile_date(self,file_path):
        # 指定 ExifTool 可执行文件的路径
        # for windows
        #exiftool_path = r"C:\Program Files\ExifTool\exiftool.exe"

        # 创建 ExifTool 对象
        #with exiftool.ExifTool(executable=exiftool_path) as et:
        # 初始化ExifTool
        with exiftool.ExifToolHelper() as et:
            # 读取视频文件的元数据
            video_file = file_path
            metadata_list = et.get_metadata(video_file)
            # 检查返回值是否为列表
            if isinstance(metadata_list, list):
                for metadata in metadata_list:
                    file_modify_date = metadata.get('QuickTime:MediaCreateDate', '')
                    # 判断字符串前五个字符是否等于"0000:"
                    if file_modify_date[:5] == "0000:":
                        print(f"File: {os.path.basename(video_file)} - File Modify Date starts with '0000:'")
                        # 提取并处理File:FileModifyDate
                        file_modify_date = metadata.get('File:FileModifyDate', '')
                        if file_modify_date:
                            # 去掉最后的'+'号
                            # print(file_modify_date)
                            # file_modify_date = file_modify_date.rstrip('+08:00')
                            if self.contains_plus_sign(file_modify_date):
                                # 有 + 号
                                file_modify_date = file_modify_date[0:19]
                                #print( file_modify_date)
                                file_modify_date = self.convert_utc_to_china_time(file_modify_date)
                                dt = datetime.strptime(file_modify_date, "%Y:%m:%d %H:%M:%S")

                                rdate = dt.strftime('%Y:%m:%d %H:%M:%S')

                            else:
                                dt = datetime.strptime(file_modify_date, "%Y:%m:%d %H:%M:%S")
                                rdate = dt.strftime('%Y:%m:%d %H:%M:%S')
                    else:
                        # 字符串转日期，指定时区
                        try:
                            # 解析日期时间字符串
                            print(file_modify_date)

                            #dt = datetime.strptime(file_modify_date, "%Y:%m:%d %H:%M:%S")
                            # 指定时区
                            #tz = pytz.timezone('Asia/Shanghai')
                            #dt = dt.astimezone(tz)
                            dt = self.convert_utc_to_china_time(file_modify_date)
                            print(dt)
                            rdate = dt
                            #print(f"File: {os.path.basename(video_file)} - Processed File Modify Date: {dt.strftime('%Y-%m-%d %H:%M:%S %Z%z')}")
                        except ValueError:
                            print(f"File: {os.path.basename(video_file)} - Invalid date format: {file_modify_date}")
                            return "err"
                    # 打印处理后的日期
                    #print(f"File: {os.path.basename(video_file)} - Processed File Modify Date: {file_modify_date}")

                    return rdate

    def contains_plus_sign(self,date_string):
        return '+' in date_string

if __name__ == '__main__':
    app = wx.App(False)
    # None)
    frame = MyFramecityymapp(None)
    #frame.Show(True)
    app.MainLoop()

